{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "dd7b6e3f",
   "metadata": {},
   "source": [
    "#### Notebook style configuration (optional)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "95c3c0cb",
   "metadata": {},
   "outputs": [],
   "source": [
    "from IPython.core.display import display, HTML\n",
    "style = open(\"./style.css\").read()\n",
    "display(HTML(\"<style>%s</style>\" % style))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e4af0b2a",
   "metadata": {},
   "source": [
    "# Dataviz catalogue\n",
    "\n",
    "In this lesson, we'll review a few of the many different types of plot matplotlib offers and manipulate them.\n",
    "\n",
    "\n",
    "<img src=\"../images/plot-basic.png\" width=\"50%\" align=\"right\" /> <img src=\"../images/plot-advanced.png\" width=\"50%\" />\n",
    "\n",
    "\n",
    "These images come from the [cheatsheets](https://github.com/matplotlib/cheatsheets).\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8df5148f",
   "metadata": {},
   "source": [
    "### Initialization\n",
    "\n",
    "Before we start, let's set some default settings such that we do not have to write them each time we start a new figure."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "235828aa",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "p = plt.rcParams\n",
    "p[\"figure.dpi\"] = 300"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "35a15d5f",
   "metadata": {},
   "source": [
    "## 1. Line plot\n",
    "\n",
    "We have already manipulated line [plot](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.plot.html) in the first lesson but we used it to render a... line plot (how surprising!). But this command is quite powerful and can be used to render many other type of plot such as, for example, a scatter plot. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1aa4d1ca",
   "metadata": {},
   "outputs": [],
   "source": [
    "X = np.random.normal(0.0, .5, 10000)\n",
    "Y = np.random.normal(0.0, .5, len(X))\n",
    "\n",
    "fig = plt.figure(figsize=(10,10))\n",
    "ax = plt.subplot()\n",
    "ax.plot(X, Y, linestyle=\"\", color=\"C1\", alpha=0.1,\n",
    "              marker=\"o\", markersize=5, markeredgewidth=0)\n",
    "\n",
    "plt.show();"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5583604d",
   "metadata": {},
   "source": [
    "In the figure above, we took advantage of the `alpha` parameter that sets the transparency level of markers. Consequently, areas with a higher number of point will be more opaque, suggesting density to the reader."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f725cf25",
   "metadata": {},
   "outputs": [],
   "source": [
    "X = [ 0,0,0,0, None, 1,1,1,1,1, None, 2,2,2, None, 3,3,3,3,3,3]\n",
    "Y = [ 1,2,3,4, None, 1,2,3,4,5, None, 1,2,3, None, 1,2,3,4,5,6]  \n",
    "\n",
    "fig = plt.figure(figsize=(10,4))\n",
    "ax = plt.subplot()\n",
    "\n",
    "ax.plot(X, Y, \"-o\", linewidth=5,\n",
    "        markersize=12, markeredgecolor=\"white\", markeredgewidth=2)\n",
    "\n",
    "ax.spines['right'].set_visible(False)\n",
    "ax.spines['left'].set_visible(False)\n",
    "ax.spines['top'].set_visible(False)\n",
    "ax.set_xlim(-.5,3.5); ax.set_xticks([0,1,2,3])\n",
    "ax.set_ylim(0,7); ax.set_yticks([])\n",
    "\n",
    "plt.show();"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b499e3e2",
   "metadata": {},
   "source": [
    "In the figure above, the important point to notice is the use of the `None` keyword in X and Y. This indicates matpltolib that we have several series and matplotlib won't draw a line between the end point of a series and the start point of the next series.\n",
    "\n",
    "\n",
    "We can also combine several line plots to create a specific effect. For example, here is a progress bar made of several plots with various parameters. Here we take advantage of very thick line and specify line capstyle."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "99b5ec0c",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = plt.figure(figsize=(10,2))\n",
    "ax = plt.subplot(frameon=False)\n",
    "\n",
    "ax.plot([1,9], [0,0], linewidth=20, color=\"black\", solid_capstyle=\"round\")\n",
    "ax.plot([1,9], [0,0], linewidth=18, color=\"white\", solid_capstyle=\"round\")\n",
    "ax.plot([1,5], [0,0], linewidth=12, color=\"C1\",    solid_capstyle=\"round\")\n",
    "ax.plot([5,6], [0,0], linewidth=12, color=\"C1\",    solid_capstyle=\"butt\")\n",
    "ax.plot([6,6], [-0.5,0.5], \"--\", linewidth=1, color=\"black\")\n",
    "\n",
    "ax.set_xlim(0,10); ax.set_xticks([])\n",
    "ax.set_ylim(-1.5,1.5); ax.set_yticks([])\n",
    "\n",
    "plt.show();"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2e5821e1",
   "metadata": {},
   "source": [
    "## 2. Scatter plot"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ab9086d8",
   "metadata": {},
   "source": [
    "We have just seen that the `plot` command can be used to draw a scatter plot and yet, there exists a [scatter](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.scatter.html) function. You may ask yourself what is the different between these two functions. In fact, the regular plot command can be used to represent as scatter plot as long as points share the same properties, i.e. share the same color and size. If for some reason we need to have different colors or sizes, then we need to use the scatter command."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e9cb6d4e",
   "metadata": {},
   "outputs": [],
   "source": [
    "T = np.random.uniform(0, 2*np.pi, 500)\n",
    "R = np.random.uniform(0.1, 0.5, len(T))\n",
    "X, Y = R*np.cos(T), R*np.sin(T)        # Position\n",
    "S = np.random.uniform(50, 350, len(X)) # Size\n",
    "V = np.arctan2(X,Y)                    # Value \n",
    "\n",
    "fig = plt.figure(figsize=(10,10))\n",
    "ax = plt.subplot(1, 1, 1)\n",
    "ax.scatter(X, Y, S, V, cmap=\"twilight\", edgecolor=\"white\")\n",
    "\n",
    "plt.show();"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c899d5ef",
   "metadata": {},
   "source": [
    "In the example above, each marker possesses its own size and color (using a colormap). We could even specify individual marker type.\n",
    "\n",
    "Scatter can thus be used to produce heat map veary easily as shown below."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c82acb8c",
   "metadata": {},
   "outputs": [],
   "source": [
    "np.random.seed(1);\n",
    "X, Y = np.arange(24), np.arange(12)\n",
    "X, Y = np.meshgrid(X,Y)\n",
    "V = np.random.uniform(50, 250, X.shape) \n",
    "\n",
    "fig = plt.figure(figsize=(10,5))\n",
    "ax = plt.subplot()\n",
    "ax.scatter(X, Y, V, V, marker='s', cmap=\"Blues\")\n",
    "\n",
    "plt.show();"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dcd24526",
   "metadata": {},
   "source": [
    "We can also add \"special effect\" like we did previously with the line plot by plotting the scatter plot several times to highlight contour."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "397d6cf4",
   "metadata": {},
   "outputs": [],
   "source": [
    "np.random.seed(1)\n",
    "X = np.random.uniform(0,10,250)\n",
    "Y = X*np.abs(np.random.normal(0,1,len(X)))**2\n",
    "\n",
    "fig = plt.figure(figsize=(10,4));\n",
    "ax = plt.subplot();\n",
    "\n",
    "ax.scatter(X, Y, 50, linewidth=5, color=\"black\", clip_on=False);\n",
    "ax.scatter(X, Y, 50, linewidth=3, color=\"white\", clip_on=False);\n",
    "ax.scatter(X, Y, 50, linewidth=0, color=\"black\", alpha=0.25, clip_on=False);\n",
    "\n",
    "ax.spines['right'].set_visible(False);\n",
    "ax.spines['left'].set_visible(False);\n",
    "ax.spines['top'].set_visible(False);\n",
    "ax.set_xlim(0,10); ax.set_xticks([0,10])\n",
    "ax.set_yticks([])\n",
    "\n",
    "plt.show();"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d7564a2d",
   "metadata": {},
   "source": [
    "Note that for this last example, we need to tell maplotlib not to clip markers that are oustide the axis (x=0 and x=10) using `clip_on=False` argument."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bf403aac",
   "metadata": {},
   "source": [
    "## 3. Image plot\n",
    "\n",
    "\n",
    "We saw in the previous section how to do a heat map using a scatter plot. If we had used a fixed marker size, we could have use it to display an image. But this would be very inefficient. Instead, we can use the dedicated function [imshow](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.imshow.html) which means image show. "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4cd90355",
   "metadata": {},
   "source": [
    "Let's first generate some data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "af4c3fe7",
   "metadata": {},
   "outputs": [],
   "source": [
    "def f(x,y,n=100):\n",
    "    X,Y = np.meshgrid(np.linspace(-3, 3, n),\n",
    "                      np.linspace(-3, 3, n))\n",
    "    return (1-X/2+X**5+Y**3)*np.exp(-X**2-Y**2)\n",
    "Z5  = f(X, Y, n=5)\n",
    "Z10 = f(X, Y, n=10)\n",
    "Z25 = f(X, Y, n=25)\n",
    "Z50 = f(X, Y, n=50)\n",
    "Z100 = f(X, Y, n=100)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b6e223f1",
   "metadata": {},
   "source": [
    "We are now ready to display them."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "20e8b5c7",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = plt.figure(figsize=(10,6))\n",
    "ax = plt.subplot(2,3,1); ax.imshow(Z5)\n",
    "ax = plt.subplot(2,3,2); ax.imshow(Z10)\n",
    "ax = plt.subplot(2,3,3); ax.imshow(Z25)\n",
    "\n",
    "plt.show();"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1fba9c0d",
   "metadata": {},
   "source": [
    "To be able to display these images, matplotlib made several implicit choices. First, you may have noticed that the limit on the axis are different on each of the three plots and do not relate to the [-3,+3] domain we used to define the image. The reason is that matpltolib has not idea where your images come from and cannot guess these limits. To solve this problem, we thus need to specify the extent of the image."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3ea824f4",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = plt.figure(figsize=(10,6))\n",
    "\n",
    "extent = [-3,+3,-3,+3]\n",
    "ax = plt.subplot(2,3,1); ax.imshow(Z5, extent=extent)     \n",
    "ax = plt.subplot(2,3,2); ax.imshow(Z10, extent=extent)\n",
    "ax = plt.subplot(2,3,3); ax.imshow(Z25, extent=extent)\n",
    "\n",
    "plt.show();"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bac7f136",
   "metadata": {},
   "source": [
    "The second choice matplotlib made concerns colors. Our arrays Z5, Z10 and Z25 are really two-dimensional scalar arrays and the question is thus, how do we map a scalar to a color? To do that, matplotlib uses what is called a colormap that map a normalized value to a given color. The default colormap is called \"viridis\" but there are [plenty of others](https://matplotlib.org/stable/tutorials/colors/colormaps.html). Let's try \"RdYlBu\"."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c0e0cc4f",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = plt.figure(figsize=(10,6))\n",
    "\n",
    "extent = [-3,+3,-3,+3]\n",
    "cmap = \"RdYlBu\"\n",
    "\n",
    "ax = plt.subplot(2,3,1); ax.imshow(Z5, extent=extent, cmap=cmap)\n",
    "ax = plt.subplot(2,3,2); ax.imshow(Z10, extent=extent, cmap=cmap)\n",
    "ax = plt.subplot(2,3,3); ax.imshow(Z25, extent=extent, cmap=cmap)\n",
    "\n",
    "plt.show();"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "98e5facf",
   "metadata": {},
   "source": [
    "On important implicit choice when displaying image is the interpolation methods between pixels composing the oputput. The default method is to use the nearest filter which results in pixelated images. This is a sane default for scientific visualization. However, in some specific case, you might want to use a smoother interpolation method and you can do so by proidivind the name to method among [those availables](https://matplotlib.org/stable/gallery/images_contours_and_fields/interpolation_methods.html?highlight=interpolation). Let's see the effect of the bicubic method."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d2f5ac50",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "fig = plt.figure(figsize=(10,6))\n",
    "\n",
    "extent = [-3,+3,-3,+3]\n",
    "cmap = \"RdYlBu\"\n",
    "interpolation = \"bicubic\"\n",
    "\n",
    "ax = plt.subplot(2,3,1);\n",
    "ax.imshow(Z5, extent=extent, cmap=cmap, interpolation=interpolation)\n",
    "ax = plt.subplot(2,3,2) \n",
    "ax.imshow(Z10, extent=extent, cmap=cmap, interpolation=interpolation)\n",
    "ax = plt.subplot(2,3,3)\n",
    "ax.imshow(Z25, extent=extent, cmap=cmap, interpolation=interpolation)\n",
    "\n",
    "plt.show();"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eb11b473",
   "metadata": {},
   "source": [
    "Since we are using a colormap we need to show how scalar values are mapped to colors and for this we need to add a colorbar. Since there are three images, we should use three colorbars because the mapping could potentially different. This is not the case here because we are using the same data in each image. But let's pretend it's not the case. To ensure the mapping is the same in all three images, we'll explicitely set what is the minimum and maximum values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cf956021",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "fig = plt.figure(figsize=(10,6))\n",
    "\n",
    "extent = [-3,+3,-3,+3]\n",
    "cmap = \"RdYlBu\"\n",
    "interpolation = \"bicubic\"\n",
    "vmin, vmax = -1, 1\n",
    "\n",
    "ax = plt.subplot(2,3,1);\n",
    "ax.imshow(Z5, extent=extent, interpolation=interpolation,\n",
    "              cmap=cmap,  vmin=vmin, vmax=vmax)\n",
    "ax = plt.subplot(2,3,2); \n",
    "ax.imshow(Z10, extent=extent, interpolation=interpolation,\n",
    "              cmap=cmap,  vmin=vmin, vmax=vmax)\n",
    "\n",
    "ax = plt.subplot(2,3,3);\n",
    "ax.imshow(Z25, extent=extent, interpolation=interpolation,\n",
    "              cmap=cmap,  vmin=vmin, vmax=vmax)\n",
    "\n",
    "plt.show();"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d28c7c52",
   "metadata": {},
   "source": [
    "Let's now display a colorbar on the left. To that, we'll use a gridspec and specify width ratio as we did in the introduction."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "350abdd4",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "from matplotlib.gridspec import GridSpec\n",
    "\n",
    "fig = plt.figure(figsize=(10,6));\n",
    "G = GridSpec(1, 4, width_ratios=(20, 20, 20, 1))\n",
    "\n",
    "extent = [-3,+3,-3,+3]\n",
    "cmap = \"RdYlBu\"\n",
    "interpolation = \"bicubic\"\n",
    "vmin, vmax = -1, 1\n",
    "\n",
    "ax = plt.subplot(G[0], aspect=1);\n",
    "I = ax.imshow(Z5, extent=extent, interpolation=interpolation,\n",
    "              cmap=cmap,  vmin=vmin, vmax=vmax)\n",
    "ax = plt.subplot(G[1], aspect=1) \n",
    "I = ax.imshow(Z10, extent=extent, interpolation=interpolation,\n",
    "              cmap=cmap,  vmin=vmin, vmax=vmax)\n",
    "ax = plt.subplot(G[2], aspect=1)\n",
    "I = ax.imshow(Z25, extent=extent, interpolation=interpolation,\n",
    "              cmap=cmap,  vmin=vmin, vmax=vmax)\n",
    "    \n",
    "plt.colorbar(I, cax=plt.subplot(G[3], aspect=20))\n",
    "\n",
    "plt.show();"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3960d13b",
   "metadata": {},
   "source": [
    "To finish our plot, let's add some contour levels using the [contour](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.contour.html) function. Since we have several arrays showing the same data with different resolution (Z5, Z10, Z25, Z50 and Z100), we can use the highest resolution to compute the contours. This will result in much smoother curves. Note that we need to vertically re-orient the contour (using the `origin` argument) such that it matches the orientation of the image."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1e27e447",
   "metadata": {},
   "outputs": [],
   "source": [
    "from matplotlib.gridspec import GridSpec\n",
    "\n",
    "fig = plt.figure(figsize=(10,6));\n",
    "G = GridSpec(1, 4, width_ratios=(20, 20, 20, 1))\n",
    "\n",
    "extent = [-3,+3,-3,+3]\n",
    "cmap = \"RdYlBu\"\n",
    "interpolation = \"bicubic\"\n",
    "vmin, vmax = -1, 1\n",
    "\n",
    "ax = plt.subplot(G[0], aspect=1);\n",
    "I = ax.imshow(Z5, extent=extent, interpolation=interpolation,\n",
    "              cmap=cmap,  vmin=vmin, vmax=vmax)\n",
    "C = ax.contour(Z100, levels=10, extent=extent, origin=\"upper\",\n",
    "               colors=\"black\", linewidths=1)\n",
    "\n",
    "ax = plt.subplot(G[1], aspect=1); \n",
    "I = ax.imshow(Z10, extent=extent, interpolation=interpolation,\n",
    "              cmap=cmap,  vmin=vmin, vmax=vmax)\n",
    "C = ax.contour(Z100, levels=10, extent=extent, origin=\"upper\",\n",
    "               colors=\"black\", linewidths=1)\n",
    "\n",
    "ax = plt.subplot(G[2], aspect=1);\n",
    "I = ax.imshow(Z25, extent=extent, interpolation=interpolation,\n",
    "              cmap=cmap,  vmin=vmin, vmax=vmax)\n",
    "C = ax.contour(Z100, levels=10, extent=extent, origin=\"upper\",\n",
    "               colors=\"black\", linewidths=1)\n",
    "    \n",
    "plt.colorbar(I, cax=plt.subplot(G[3], aspect=20))\n",
    "\n",
    "plt.show();"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "76a4a0d6",
   "metadata": {},
   "source": [
    "There are many other things that can be done with imshow & contour and we'll some later in the advanced matplotlib series."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0d9ee36f",
   "metadata": {},
   "source": [
    "## 4. Bar plot\n",
    "\n",
    "We'll finish this lesson with [bar](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.bar.html) plots that are omnipresent in the scientific litterature in order to represent quantities or histograms.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b08cd88a",
   "metadata": {},
   "outputs": [],
   "source": [
    "np.random.seed(1)\n",
    "X = np.arange(0,10)\n",
    "Y = np.random.uniform(0.5, 1.0, len(X))\n",
    "\n",
    "fig = plt.figure(figsize=(10,4))\n",
    "ax = plt.subplot()\n",
    "\n",
    "ax.bar(X, Y)\n",
    "\n",
    "ax.spines['right'].set_visible(False)\n",
    "ax.spines['left'].set_visible(False)\n",
    "ax.spines['top'].set_visible(False)\n",
    "ax.set_xticks(X)\n",
    "ax.set_yticks([])\n",
    "\n",
    "plt.show();"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d4d13d9e",
   "metadata": {},
   "source": [
    "When your date represents a mean, it is quite common to represent the standard deviation using an error bar."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7ed1769d",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "np.random.seed(1)\n",
    "X = np.arange(0,10)\n",
    "Y = np.random.uniform(0.5, 1.0, (len(X),10))\n",
    "\n",
    "fig = plt.figure(figsize=(10,4))\n",
    "ax = plt.subplot();\n",
    "\n",
    "ax.bar(X, Y.mean(axis=1), color=\"C0\", yerr=Y.std(axis=1), \n",
    "       error_kw=dict(ecolor=\"C0\", linewidth=3, capsize=5, capthick=3))\n",
    "\n",
    "ax.spines['right'].set_visible(False)\n",
    "ax.spines['left'].set_visible(False)\n",
    "ax.spines['top'].set_visible(False)\n",
    "ax.set_xticks(X)\n",
    "ax.set_yticks([])\n",
    "\n",
    "plt.show();"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1f6e097a",
   "metadata": {},
   "source": [
    "It is also common to have several series that need to be grouped. To do that, we can use several bar plots and play with the X coordinate."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9a106d2d",
   "metadata": {},
   "outputs": [],
   "source": [
    "np.random.seed(1)\n",
    "X = np.arange(0,5)\n",
    "Y1 = np.random.uniform(0.5, 1.0, len(X))\n",
    "Y2 = np.random.uniform(0.5, 1.0, len(X))\n",
    "Y3 = np.random.uniform(0.5, 1.0, len(X))\n",
    "Y4 = np.random.uniform(0.5, 1.0, len(X))\n",
    "       \n",
    "fig = plt.figure(figsize=(10,4));\n",
    "ax = plt.subplot();\n",
    "\n",
    "ax.bar(X*5,   Y1, color=\"C0\", alpha=1.00)\n",
    "ax.bar(X*5+1, Y2, color=\"C0\", alpha=0.75)\n",
    "ax.bar(X*5+2, Y3, color=\"C0\", alpha=0.50)\n",
    "ax.bar(X*5+3, Y4, color=\"C0\", alpha=0.25)\n",
    "\n",
    "ax.set_xticks(X*5+1.5)\n",
    "ax.set_xticklabels([\"2015\",\"2016\",\"2017\",\"2018\",\"2019\"])\n",
    "ax.set_yticks([])\n",
    "\n",
    "plt.show();"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2e01123b",
   "metadata": {},
   "source": [
    "Similarly, we can further modify the plot with additional series below using a negative height."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b9eb599a",
   "metadata": {},
   "outputs": [],
   "source": [
    "np.random.seed(1)\n",
    "X = np.arange(0,5)\n",
    "Y1 = np.random.uniform(0.25, 1.0, len(X))\n",
    "Y2 = np.random.uniform(0.25, 1.0, len(X))\n",
    "Y3 = np.random.uniform(0.25, 1.0, len(X))\n",
    "Y4 = np.random.uniform(0.25, 1.0, len(X))\n",
    "Y5 = np.random.uniform(0.25, 1.0, len(X))\n",
    "Y6 = np.random.uniform(0.25, 1.0, len(X))\n",
    "Y7 = np.random.uniform(0.25, 1.0, len(X))\n",
    "Y8 = np.random.uniform(0.25, 1.0, len(X))\n",
    "       \n",
    "fig = plt.figure(figsize=(10,4));\n",
    "ax = plt.subplot();\n",
    "\n",
    "ax.bar(X*5,    Y1, color=\"C0\", alpha=1.00)\n",
    "ax.bar(X*5+1,  Y2, color=\"C0\", alpha=0.75)\n",
    "ax.bar(X*5+2,  Y3, color=\"C0\", alpha=0.50)\n",
    "ax.bar(X*5+3,  Y4, color=\"C0\", alpha=0.25)\n",
    "ax.bar(X*5,   -Y5, color=\"C1\", alpha=1.00)\n",
    "ax.bar(X*5+1, -Y6, color=\"C1\", alpha=0.75)\n",
    "ax.bar(X*5+2, -Y7, color=\"C1\", alpha=0.50)\n",
    "ax.bar(X*5+3, -Y8, color=\"C1\", alpha=0.25)\n",
    "\n",
    "ax.spines['right'].set_visible(False)\n",
    "ax.spines['left'].set_visible(False)\n",
    "ax.spines['top'].set_visible(False)\n",
    "ax.spines['bottom'].set_position((\"data\",0))\n",
    "\n",
    "ax.set_xticks([])\n",
    "ax.set_yticks([])\n",
    "\n",
    "plt.show();"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "08167a87",
   "metadata": {},
   "source": [
    "Bar plot can be also oriented horizontally using the `barh` function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "311a738e",
   "metadata": {},
   "outputs": [],
   "source": [
    "np.random.seed(1)\n",
    "X = np.arange(0,25)\n",
    "Y1 = np.random.uniform(75, 100, len(X))*(25-X)\n",
    "Y2 = np.random.uniform(75, 100, len(X))*(25-X)\n",
    "\n",
    "fig = plt.figure(figsize=(10,5))\n",
    "ax = plt.subplot(1,1,1);\n",
    "\n",
    "ax.barh(X, +Y1, color=\"C1\")\n",
    "ax.barh(X, -Y2, color=\"C3\")\n",
    "\n",
    "ax.spines['right'].set_visible(False);\n",
    "ax.spines['top'].set_visible(False);\n",
    "ax.spines['left'].set_position((\"data\",0))\n",
    "\n",
    "ax.set_ylim(-0.5, len(X))\n",
    "ax.set_xticks([-2000,-1000,0, 1000,2000]);\n",
    "ax.set_xticklabels([\"2000\",\"1000\",\"0\", \"1000\",\"2000\"])\n",
    "ax.set_yticks([])\n",
    "\n",
    "plt.show();"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "199df727",
   "metadata": {},
   "source": [
    "We have only scratched the surface of matplotlib and there exist many other type of plots that might be useful depending on your scientific domain. To learn about them, best is to have a look at the [cheatsheets](https://github.com/rougier/matplotlib-cheatsheet) and the [gallery](https://matplotlib.org/stable/gallery/index.html)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ccc901a1",
   "metadata": {},
   "source": [
    "## 5. Exercises"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ca99a653",
   "metadata": {},
   "source": [
    "### 5.1 Regular hexagonal scatter\n",
    "\n",
    "Since there exists an hexagonal marker ( `h` ), it is almost straightforward to create a regular hexagonal scatter plot as shown below. Try to reproduce the figure below by first placing the marker with the right size and then try to color them.\n",
    "\n",
    "<img src=\"../images/02-exercise-1.png\" width=\"100%\" />"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8e644d93",
   "metadata": {},
   "source": [
    "### 5.2 Scatter-bar\n",
    "\n",
    "We can mix scatter and bar plot to better represent data dispersion around the mean. Try to reproduce the figure below with the exact same appearance.\n",
    "\n",
    "<img src=\"../images/02-exercise-2.png\" width=\"100%\" />"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1d2e3486",
   "metadata": {},
   "source": [
    "### 5.3 Mona Lisa variations\n",
    "\n",
    "Using the [imread](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.imread.html) function and the provide Mona Lisa [image](../images/MonaLisa.jpg), try to reproduce the figure below. Be careful with the image pixel format (RGBA). If you want to use a colormap, you need to extract a single channel.\n",
    "\n",
    "\n",
    "<img src=\"../images/02-exercise-3.png\" width=\"100%\" />"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2b5c0eb9",
   "metadata": {},
   "source": [
    "----\n",
    "\n",
    "**Copyright (c) 2021 Nicolas P. Rougier**    \n",
    "This work is licensed under a [Creative Commons Attribution 4.0 International License](http://creativecommons.org/licenses/by/4.0/).\n",
    "<br/>\n",
    "Code is licensed under a [2-Clauses BSD license](https://opensource.org/licenses/BSD-2-Clause)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
